package com.obas.business.element.service.impl;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

import com.ease.common.vo.MapParameter;
import com.ease.common.vo.Pagination;
import com.ease.dao.jdbctemplate.rowmapper.ParameterizedBeanPropertyRowMapper;
import com.ease.platform.access.service.impl.AbstractNamespaceJdbcTemplateAccessServiceImpl;
import com.obas.access.business.service.CircuitAccessService;
import com.obas.access.business.service.CustomerAccessService;
import com.obas.access.business.service.DeviceAccessService;
import com.obas.business.common.support.PaginationHandlerCallback;
import com.obas.business.concurrent.service.ConcurrentProcessChainService;
import com.obas.business.element.service.ElementMacAddressProcessService;
import com.obas.model.business.Circuit;
import com.obas.model.business.Device;
import com.obas.model.intermediate.ElementUserMacAddress;
import com.obas.model.intermediate.UserMacAddressDeviceRank;
import com.obas.model.type.BatchTimestampAware;

public class ElementMacAddressProcessServiceImpl extends AbstractNamespaceJdbcTemplateAccessServiceImpl implements ElementMacAddressProcessService {

	final static class Statement {

		static String addDeviceByBatchTimestamp = "addDeviceByBatchTimestamp";

		static String removeElementUserMacAddressByBatchTimestamp = "removeElementUserMacAddressByBatchTimestamp";

		static String addElementUserMacAddressByBatchTimestamp = "addElementUserMacAddressByBatchTimestamp";

		static String removeElementDeviceRankByBatchTimestamp = "removeElementDeviceRankByBatchTimestamp";

		//
		static String removeElementMacAddressDeviceByBatchTimestamp = "removeElementMacAddressDeviceByBatchTimestamp";

		static String addElementMacAddressDeviceByBatchTimestamp = "addElementMacAddressDeviceByBatchTimestamp";

		//
		static String addElementDeviceRankByBatchTimestamp = "addElementDeviceRankByBatchTimestamp";

		static String countElementUserMacAddressByBatchTimestamp = "countElementUserMacAddressByBatchTimestamp";

		//
		static String findUserMacAddressDeviceRank = "findUserMacAddressDeviceRank";

	}

	private ConcurrentProcessChainService concurrentProcessChainService;

	private CustomerAccessService customerAccessService;

	private DeviceAccessService deviceAccessService;

	private CircuitAccessService circuitAccessService;

	public void process(final Date batchTimestamp) {

		// TAG upstreamPort and nonUserMacAddress /UserMacAddress

		MapParameter parameter = null;
		{
			parameter = new MapParameter();
			parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
			this.getJdbcTemplateDataAccessObject().execute(statement(Statement.addDeviceByBatchTimestamp), parameter);
		}

		{
			parameter = new MapParameter();
			parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
			this.getJdbcTemplateDataAccessObject().remove(statement(Statement.removeElementUserMacAddressByBatchTimestamp), parameter);

			parameter = new MapParameter();
			parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
			this.getJdbcTemplateDataAccessObject().execute(statement(Statement.addElementUserMacAddressByBatchTimestamp), parameter);
		}
		{
			parameter = new MapParameter();
			parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
			this.getJdbcTemplateDataAccessObject().remove(statement(Statement.removeElementMacAddressDeviceByBatchTimestamp), parameter);

			parameter = new MapParameter();
			parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
			this.getJdbcTemplateDataAccessObject().execute(statement(Statement.addElementMacAddressDeviceByBatchTimestamp), parameter);
		}
		{
			parameter = new MapParameter();
			parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
			this.getJdbcTemplateDataAccessObject().remove(statement(Statement.removeElementDeviceRankByBatchTimestamp), parameter);

			parameter = new MapParameter();
			parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
			this.getJdbcTemplateDataAccessObject().execute(statement(Statement.addElementDeviceRankByBatchTimestamp), parameter);
		}

		new PaginationHandlerCallback() {

			public int count() {
				MapParameter parameter = new MapParameter();
				parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);
				return ElementMacAddressProcessServiceImpl.this.getJdbcTemplateDataAccessObject().count(statement(Statement.countElementUserMacAddressByBatchTimestamp), parameter);
			}

			public void onPagination(int paginationIndex) {
				// ElementMacAddressProcessServiceImpl.this.concurrentProcessChainService.execute(new
				// ConcurrentRetailCallback<Object>() {
				// public Object execute() throws Throwable {
				ElementMacAddressProcessServiceImpl.this.processNetworkCircuitByUserMacAddress(paginationIndex, batchTimestamp);
				// return null;
				// }
				// });

			}
		}.handle();

	}

	public void processNetworkCircuitByUserMacAddress(int paginationIndex, Date batchTimestamp) {

		MapParameter parameter = null;

		Pagination<ElementUserMacAddress> pagination = new Pagination<ElementUserMacAddress>();
		pagination.setIndex(paginationIndex);
		pagination.setSize(PaginationHandlerCallback.TASK_PAGINATION_SIZE);
		int skipResult = pagination.getStart();
		int maxResult = pagination.getStart() + pagination.getSize();

		parameter = new MapParameter();
		parameter.put("skipResult", skipResult);
		parameter.put("maxResult", maxResult);
		parameter.put(BatchTimestampAware.batchTimestamp, batchTimestamp);

		List<UserMacAddressDeviceRank> userMacAddressDeviceRanks = this.getJdbcTemplateDataAccessObject().find(statement(Statement.findUserMacAddressDeviceRank), parameter,
				ParameterizedBeanPropertyRowMapper.newInstance(UserMacAddressDeviceRank.class));

		// List<Map<String, Object>> userMacAddressDeviceRanks1 =
		// this.getJdbcTemplateDataAccessObject().find(statement(Statement.findUserMacAddressDeviceRank), parameter
		// );
		//
		// List<UserMacAddressDeviceRank> userMacAddressDeviceRanks = null;
		if (null == userMacAddressDeviceRanks) {
			return;
		}

		Iterator<UserMacAddressDeviceRank> iterator = userMacAddressDeviceRanks.iterator();
		UserMacAddressDeviceRank previous = null;
		while (iterator.hasNext()) {
			UserMacAddressDeviceRank current = iterator.next();
			if (null != previous) {
				if (rankGreaterThan(previous, current)) {
					if (previous.getDeviceId() <= 0) {
						Device previousDevice = deviceAccessService.findByCode(previous.getDeviceCode());
						if (null != previousDevice) {
							previous.setDeviceId(previousDevice.getId());
						}
					}
					if (current.getDeviceId() <= 0) {
						Device currentDevice = deviceAccessService.findByCode(current.getDeviceCode());
						if (null != currentDevice) {
							current.setDeviceId(currentDevice.getId());
						}
					}

					List<Circuit> circuits = this.circuitAccessService.findByAendDeviceIdZendDeviceId(previous.getDeviceId(), current.getDeviceId());
					if (notEmpty(circuits)) {
						// TBD delete redudency circuit
					} else {
						Circuit circuit = new Circuit();
						circuit.setCode(previous.getDeviceCode() + "<->" + current.getDeviceCode());
						circuit.setName(circuit.getCode());
						circuit.setAendDeviceId(previous.getDeviceId());
						circuit.setZendDeviceId(current.getDeviceId());

						this.circuitAccessService.create(circuit);
					}

				}
			}
			previous = current;
		}

	}

	public static boolean rankGreaterThan(UserMacAddressDeviceRank previous, UserMacAddressDeviceRank current) {
		if (previous.getDeviceCode().equals(current.getDeviceCode())) {
			return false;
		}

		if (previous.getTypeRank() > current.getTypeRank()) {
			return true;
		}

		if (previous.getRank() > current.getRank()) {
			return true;
		}

		return false;
	}

	/**
	 * @return the concurrentProcessChainService
	 */
	public ConcurrentProcessChainService getConcurrentProcessChainService() {
		return concurrentProcessChainService;
	}

	/**
	 * @param concurrentProcessChainService
	 *            the concurrentProcessChainService to set
	 */
	public void setConcurrentProcessChainService(ConcurrentProcessChainService concurrentProcessChainService) {
		this.concurrentProcessChainService = concurrentProcessChainService;
	}

	/**
	 * @return the customerAccessService
	 */
	public CustomerAccessService getCustomerAccessService() {
		return customerAccessService;
	}

	/**
	 * @param customerAccessService
	 *            the customerAccessService to set
	 */
	public void setCustomerAccessService(CustomerAccessService customerAccessService) {
		this.customerAccessService = customerAccessService;
	}

	/**
	 * @return the deviceAccessService
	 */
	public DeviceAccessService getDeviceAccessService() {
		return deviceAccessService;
	}

	/**
	 * @param deviceAccessService
	 *            the deviceAccessService to set
	 */
	public void setDeviceAccessService(DeviceAccessService deviceAccessService) {
		this.deviceAccessService = deviceAccessService;
	}

	/**
	 * @return the circuitAccessService
	 */
	public CircuitAccessService getCircuitAccessService() {
		return circuitAccessService;
	}

	/**
	 * @param circuitAccessService
	 *            the circuitAccessService to set
	 */
	public void setCircuitAccessService(CircuitAccessService circuitAccessService) {
		this.circuitAccessService = circuitAccessService;
	}

	public void batchProcess(Date batchTimestamp) {
		this.process(batchTimestamp);
	}

}
